<template>
	<view class="month-calendar" :style="{
      position: sticky ? 'sticky' : 'static',
      top: sticky ? top + 'rpx' : null,
      zIndex: sticky ? 100 : null,
      '--color': color ? color : '#757575',
    }">
		<view class="calendar-box" :style="{
        background: bgColor,
        '--watermark': `'${currentYear}年${
          currentMonth > 9 ? currentMonth : '0' + currentMonth
        }月'`,
        '--showWatermark': watermark ? 'block' : 'none',
      }">
			<view v-if="mode === 'week'" class="calendar-heander" :style="{
          justifyContent: align == 'center' ? 'center' : 'space-between',
        }">

				<template v-if="align == 'center'">
					<view class="before" />
					<view class="title">{{ timeStr }}</view>
					<view class="after" />
				</template>
				<template v-if="align == 'left'">
					{{ timeStr }}
				</template>
				<view class="back-today" @click="goback" v-if="showBack && isToday && align === 'left'">
					回到今天
				</view>
			</view>
			<view v-if="mode === 'month'" class="calendar-heander-month">
				<view class="arrow" @click="daysPre" />
				{{ currentYear }}年{{ currentMonth > 9 ? currentMonth : '0' + currentMonth }}月
				<view class="arrow" @click="daysNext" />
			</view>
			<view class="calendar-weeks">
				<view class="calendar-week" v-for="(week, index) in weeks" :key="index" :style="{
            color: color ? color : '#34485e',
          }">
					{{ week }}
				</view>
			</view>
			<view class="calendar-content">
				<swiper class="calendar-swiper" :style="{
            width: '100%',
            height: sheight,
          }" :indicator-dots="false" :autoplay="false" :duration="duration" :current="current" @change="changeSwp"
					:circular="true">
					<swiper-item class="calendar-item" v-for="sitem in swiper" :key="sitem">
						<view class="calendar-days">
							<template v-if="sitem === current">
								<view class="calendar-day" v-for="(item, index) in days" :key="index" :class="{
                    'day-hidden': !item.show,
                  }" @click="clickItem(item)">
									<view class="date" :class="[
                      item.isToday ? todayClass : '',
                      item.fullDate === selectedDate ? checkedClass : '',
                    ]">
										{{ item.time.getDate() }}
									</view>
									<view class="dot-show" v-if="item.info" :style="dotStyle"> </view>
								</view>
							</template>
							<template v-else>
								<template v-if="current - sitem === 1 || current - sitem === -2">
									<view class="calendar-day" v-for="(item, index) in predays" :key="index" :class="{
                      'day-hidden': !item.show,
                    }">
										<view class="date" :class="[item.isToday ? todayClass : '']">
											{{ item.time.getDate() }}
										</view>
									</view>
								</template>
								<template v-else>
									<view class="calendar-day" v-for="(item, index) in nextdays" :key="index" :class="{
                      'day-hidden': !item.show,
                    }">
										<view class="date" :class="[item.isToday ? todayClass : '']">
											{{ item.time.getDate() }}
										</view>
									</view>
								</template>
							</template>
						</view>
					</swiper-item>
				</swiper>
				<view v-if="more" class="mode-change">
					<view :style="{
              transform: `rotate(${weekMode ? 90 : 270}deg)`,
            }" @click="changeMode">
						》
					</view>
				</view>
			</view>
		</view>
		<slot>
			<!-- 默认插槽 -->
		</slot>
		<view class="cal-button" v-if="showBack && isToday && align === 'center'" @click="goback">
			今
		</view>
	</view>
</template>
<script setup>
	import {
		ref,
		computed,
		watch,
		onMounted
	} from "vue";
	import {
		gegerateDates,
		dateEqual,
		formatDate
	} from "./generateDates.js";

	const weeks = ref(["一", "二", "三", "四", "五", "六", "日"]);
	const current = ref(1);
	const currentYear = ref("");
	const currentMonth = ref("");
	const currentDate = ref("");
	const days = ref([]);
	const weekMode = ref(true);
	const swiper = ref([0, 1, 2]);
	const selectedDate = ref(formatDate(new Date(), "yyyy-MM-dd"));

	const props = defineProps({
		// 滚动速度ms
		duration: {
			type: Number,
			default: 500,
		},
		// 打点日期列表
		dotList: {
			type: Array,
			default: () => [],
		},
		// 显示返回今日
		showBack: {
			type: Boolean,
			default: false,
		},
		// 自定义今日样式
		todayClass: {
			type: String,
			default: "is-today",
		},
		// 选中日期的样式
		checkedClass: {
			type: String,
			default: "is-checked",
		},
		// 是否吸顶
		sticky: {
			type: Boolean,
			default: false,
		},
		// 吸顶距离(开启吸顶生效)
		top: {
			type: [String, Number],
			default: 0,
		},
		// 日历视图类型
		mode: {
			type: String,
			default: "week",
		},
		// 显示更多按钮
		more: {
			type: Boolean,
			default: true,
		},
		// 标记日期的自定义样式
		dotStyle: {
			type: Object,
			default () {
				return {
					background: "#4EA770",
				};
			},
		},
		// 背景色
		bgColor: {
			type: String,
			default: "#fff",
		},
		// 文本颜色
		color: {
			type: String,
			default: "",
		},
		// 对齐方式
		align: {
			type: String,
			default: "left",
		},
		// 显示水印
		watermark: {
			type: Boolean,
			default: false,
		},
	});

	const emit = defineEmits(["days-change", "selected-change"]);

	watch(
		props,
		(val) => {
			if (val.dotList) {
				setTimeout(() => {
					let list = days.value.slice(0) || [];

					list = list?.map(i => {
						return {
							...i,
							info: ''
						}
					});
					val.dotList.forEach((d) => {
						const index = list.findIndex((i) => i.fullDate == d);
						if (index >= 0) list[index].info = d;
					});
					days.value = list;
				}, 0);
			}
		}, {
			deep: true,
			immediate: true
		}
	);

	onMounted(() => {
		if (props.mode === "month") {
			weekMode.value = false;
		} else {
			weekMode.value = true;
		}
		initDate();
	});

	// 日历高度
	const sheight = computed(() => {
		// 判断该月有多少天
		let h = "80rpx";
		if (!weekMode.value) {
			const d = new Date(currentYear.value, currentMonth.value, 0);
			const days = d.getDate(); // 判断本月有多少天
			let day = new Date(d.setDate(1)).getDay();
			if (day === 0) day = 7;
			const pre = 8 - day;
			const rows = Math.ceil((days - pre) / 7) + 1;
			h = 80 * rows + "rpx";
		}
		return h;
	});

	// 当前年月
	const timeStr = computed(() => {
		let choose = new Date(selectedDate.value);
		const y = choose.getFullYear();
		const m =
			choose.getMonth() + 1 <= 9 ? `0${choose.getMonth() + 1}` : choose.getMonth() + 1;
		const d = choose.getDate() <= 9 ? `0${choose.getDate()}` : choose.getDate();
		return props.mode === "month" ?
			`${y}年${m}月` :
			props.align == "center" ?
			`${y}-${m}-${d}` :
			`${y} | ${m}.${d}`;
	});

	// 上个月天数
	const predays = computed(() => {
		let pres = [];
		if (weekMode.value) {
			const d = new Date(currentYear.value, currentMonth.value - 1, currentDate.value);
			d.setDate(d.getDate() - 7);
			pres = gegerateDates(d, "week");
		} else {
			const d = new Date(currentYear.value, currentMonth.value - 2, 1);
			pres = gegerateDates(d, "month");
		}
		return pres;
	});

	// 下个月天数
	const nextdays = computed(() => {
		let nexts = [];
		if (weekMode.value) {
			const d = new Date(currentYear.value, currentMonth.value - 1, currentDate.value);
			d.setDate(d.getDate() + 7);
			nexts = gegerateDates(d, "week");
		} else {
			const d = new Date(currentYear.value, currentMonth.value, 1);
			nexts = gegerateDates(d, "month");
		}
		return nexts;
	});

	// 是否是今天
	const isToday = computed(() => {
		const d = new Date();
		const day = formatDate(d, "yyyy-MM-dd");
		return day != selectedDate.value;
	});

	// 切换月份/周
	const changeSwp = (e) => {
		const pre = current.value;
		const cur = e.detail.current;
		/* 根据前一个减去目前的值我们可以判断是下一个月/周还是上一个月/周
		 *cur - pre === 1, -2时是下一个月/周
		 *cur -pre === -1, 2时是上一个月或者上一周
		 */
		current.value = cur;
		console.log(pre, cur);
		if (cur - pre === 1 || cur - pre === -2) {
			daysNext();
		} else {
			daysPre();
		}
	};
	// 初始化日历的方法
	const initDate = (cur) => {
		let date = "";
		if (cur) {
			date = new Date(cur);
		} else {
			date = new Date();
		}
		currentDate.value = date.getDate();
		currentYear.value = date.getFullYear();
		currentMonth.value = date.getMonth() + 1;
		days.value = [];
		let list = [];
		if (weekMode.value) {
			list = gegerateDates(date, "week");
		} else {
			list = gegerateDates(date, "month");
		}
		list.forEach((day) => {
			const dot = props.dotList.find((i) => {
				return dateEqual(i, day.fullDate);
			});
			if (dot) day.info = dot;
		});
		days.value = list;
		//  派发事件,时间发生改变
		let obj = {
			start: "",
			end: "",
		};
		if (weekMode.value) {
			obj.start = days.value[0].time;
			obj.end = days.value[6].time;
		} else {
			const start = new Date(currentYear.value, currentMonth.value - 1, 1);
			const end = new Date(currentYear.value, currentMonth.value, 0);
			obj.start = start;
			obj.end = end;
		}
		emit("days-change", obj);
	};
	//  上一个
	const daysPre = () => {
		if (weekMode.value) {
			const d = new Date(currentYear.value, currentMonth.value - 1, currentDate.value);
			d.setDate(d.getDate() - 7);
			initDate(d);
		} else {
			const d = new Date(currentYear.value, currentMonth.value - 2, 1);
			initDate(d);
		}
	};
	//  下一个
	const daysNext = () => {
		if (weekMode.value) {
			const d = new Date(currentYear.value, currentMonth.value - 1, currentDate.value);
			d.setDate(d.getDate() + 7);
			initDate(d);
		} else {
			const d = new Date(currentYear.value, currentMonth.value, 1);
			initDate(d);
		}
	};
	// 切换模式
	const changeMode = () => {
		const premode = weekMode.value;
		let isweek = false;
		if (premode) {
			isweek = !!days.value.find((i) => i.fullDate === selectedDate.value);
		}
		weekMode.value = !weekMode.value;
		let d = new Date(currentYear.value, currentMonth.value - 1, currentDate.value);
		const sel = new Date(selectedDate.value.replace("-", "/").replace("-", "/"));
		const isMonth =
			sel.getFullYear() === currentYear.value && sel.getMonth() + 1 === currentMonth.value;
		if ((selectedDate.value && isMonth) || isweek) {
			d = new Date(selectedDate.value.replace("-", "/").replace("-", "/"));
		}
		initDate(d);
	};
	// 点击日期
	const clickItem = (e) => {
		selectedDate.value = e.fullDate;
		emit("selected-change", e.fullDate);
	};
	// 回到今天
	const goback = () => {
		const d = new Date();
		selectedDate.value = formatDate(d, "yyyy-MM-dd");
		emit("selected-change", formatDate(d, "yyyy-MM-dd"));
		initDate(d);
	};
</script>

<style lang="scss" scoped>
	.month-calendar {
		--watermark: "";
		--showWatermark: none;
		--color: #757575;
		width: 100%;
		height: auto;
		background: #fff;
		overflow: hidden;
		box-shadow: 0 0 20rpx 2rpx rgba(117, 117, 117, 0.16);
		border-radius: 20rpx;
		margin-bottom: 30rpx;

		.calendar-box {
			position: relative;

			&::after {
				content: var(--watermark);
				display: var(--showWatermark);
				position: absolute;
				top: 50%;
				left: 0;
				right: 0;
				text-align: center;
				transform: translateY(-50%);
				color: rgba(0, 0, 0, 0.2);
				/* 设置水印文字颜色和透明度 */
				font-size: 100rpx;
				pointer-events: none;
			}
		}

		.calendar-heander {
			height: 80rpx;
			line-height: 80rpx;
			font-size: 30rpx;
			color: #6b7897;
			font-size: 28rpx;
			padding: 0 20rpx;
			display: flex;
			justify-content: space-between;
			align-items: center;

			.title {
				color: var(--color);
				padding: 0 10rpx;
				font-size: 32rpx;
				font-weight: 600;
			}

			.before {
				width: 12rpx;
				height: 24rpx;
				margin-right: 10rpx;
				display: inline-block;
				background-color: var(--color);
				position: relative;
				border-radius: 8rpx;

				&::before {
					content: "";
					position: absolute;
					left: -20rpx;
					top: 8rpx;
					width: 12rpx;
					height: 16rpx;
					display: inline-block;
					border-radius: 8rpx;
					background-color: var(--color);
				}
			}

			.after {
				width: 12rpx;
				height: 24rpx;
				margin-left: 10rpx;
				display: inline-block;
				background-color: var(--color);
				position: relative;
				border-radius: 8rpx;

				&::before {
					content: "";
					position: absolute;
					left: 20rpx;
					top: 8rpx;
					width: 12rpx;
					height: 16rpx;
					display: inline-block;
					border-radius: 8rpx;
					background-color: var(--color);
				}
			}
		}

		.calendar-heander-month {
			height: 120rpx;
			line-height: 120rpx;
			font-size: 30rpx;
			color: #6b7897;
			font-size: 28rpx;
			padding: 0 20rpx;
			display: flex;
			justify-content: center;
			align-items: center;

			.arrow {
				width: 42rpx;
				height: 42rpx;
				border-radius: 50%;
				background-color: #f7f8fc;
				display: flex;
				justify-content: center;
				align-items: center;

				&:active {
					background-color: #f5f5f5;
				}

				&:first-child {
					margin-right: 60rpx;

					&::before {
						content: "";
						width: 16rpx;
						height: 16rpx;
						border-top: 0 solid #4ea770;
						border-right: 0 solid #4ea770;
						border-left: 4rpx solid #4ea770;
						border-bottom: 4rpx solid #4ea770;
						transform: rotate(45deg);
						margin-left: 6rpx;
					}
				}

				&:last-child {
					margin-left: 60rpx;

					&::after {
						content: "";
						width: 16rpx;
						height: 16rpx;
						border-top: 4rpx solid #4ea770;
						border-right: 4rpx solid #4ea770;
						border-left: 0 solid #4ea770;
						border-bottom: 0 solid #4ea770;
						transform: rotate(45deg);
						margin-right: 6rpx;
					}
				}
			}
		}

		.calendar-weeks {
			width: 100%;
			display: flex;
			flex-flow: row nowrap;
			height: 60rpx;
			line-height: 60rpx;
			justify-content: center;
			align-items: center;

			.calendar-week {
				width: calc(100% / 7);
				height: 100%;
				font-size: 30rpx;
				text-align: center;
			}
		}

		swiper {
			width: 100%;
			height: 60rpx;
		}

		.calendar-content {
			min-height: 100rpx;
		}

		.calendar-swiper {
			min-height: 90rpx;
			transition: height ease-out 0.3s;
		}

		.calendar-item {
			margin: 0;
			padding: 0;
			height: 100%;
		}

		.calendar-days {
			display: flex;
			flex-flow: row wrap;
			width: 100%;
			height: 100%;
			overflow: hidden;
			font-size: 28rpx;

			.calendar-day {
				width: calc(100% / 7);
				height: 80rpx;
				text-align: center;
				display: flex;
				flex-flow: column nowrap;
				justify-content: flex-start;
				align-items: center;
			}
		}

		.day-hidden {
			visibility: hidden;
		}

		.mode-change {
			display: flex;
			justify-content: center;
			margin-top: 10rpx;

			view {
				color: #bdbdbd;
				font-size: 40rpx;
				transition: transform 0.3s;
				margin-bottom: 10rpx;
			}
		}

		.date {
			width: 60rpx;
			height: 60rpx;
			line-height: 60rpx;
			margin: 0 auto;
			font-size: 28rpx;
			border-radius: 60rpx;
			color: var(--color);
		}

		.is-today {
			border-radius: 50%;
			color: #4ea770;
		}

		.dot-show {
			margin-top: 6rpx;
			width: 12rpx;
			height: 12rpx;
			background: #c6c6c6;
			border-radius: 50%;
		}

		.is-checked {
			background: #4ea770;
			color: #ffffff;
		}
	}

	.cal-button {
		width: 80rpx;
		height: 80rpx;
		border-radius: 50%;
		font-size: 28rpx;
		display: flex;
		justify-content: center;
		align-items: center;
		color: var(--color);
		background-color: #4ea770;
		position: fixed;
		bottom: 200rpx;
		right: 40rpx;
	}
</style>